package EmailService;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.util.Date;
import java.util.Properties;


public class MailSender {

    /**
     * 以纯文本形式发送邮件
     * @param info 发送邮件的信息
     * @throws MessagingException
     */
    public static void sendTextMail(SendInfo info) throws MessagingException{
        Message message = initMessage(info);
        message.setText(info.getMailContent());
        transport(message);
    }

    /**
     * 以HTML格式发送复杂邮件，包括图片和附件（可选）
     * @param info
     * @throws MessagingException
     */
    public static void sendMutiMail(SendInfo info) throws Exception{

        Message message = initMessage(info);
        /**
         * MiniMutipart类是一个容器类，包含MimeBodyPart类型的对象
         * 创建一个包含HTML内容的MimeBodyPart
         * text 文本
         * image 图片
         * file 附件
         */
        MimeMultipart mailContent = new MimeMultipart("mixed");// 附件
        message.setContent(mailContent);

        // 附件(利用jaf框架读取数据源生成邮件体)
        if(info.getAttachFileNames()!=null){
            for(String fileName : info.getAttachFileNames()){
                // 附件
                MimeBodyPart file = new MimeBodyPart();
                DataSource source = new FileDataSource(fileName);// 附件路径
                DataHandler handler = new DataHandler(source);
                file.setFileName(MimeUtility.encodeText(fileName));
                file.setDataHandler(handler);
                // 将附件添加到邮件中
                mailContent.addBodyPart(file);
            }
        }

        // 内容
        MimeBodyPart mailBody = new MimeBodyPart();
        // 将内容添加到邮件当中
        mailContent.addBodyPart(mailBody);

        // 邮件正文（内嵌图片+html文本）
        MimeMultipart body = new MimeMultipart("related");// 内嵌资源
        mailBody.setContent(body);

        if(info.getAttachImageNames()!=null){
            // i作为索引值设置cid
            for(int i = 0;i<info.getAttachImageNames().size();i++){
                // 内嵌图片
                MimeBodyPart imgPart = new MimeBodyPart();
                DataSource imgSource = new FileDataSource(info.getAttachImageNames().get(i));// 正文图片路径
                DataHandler imgHandler = new DataHandler(imgSource);
                imgPart.setDataHandler(imgHandler);
                imgPart.setContentID("img_" + i);
                // 将内嵌图片添加到邮件内容中
                body.addBodyPart(imgPart);

            }
        }

        // html文本
        MimeBodyPart htmlPart = new MimeBodyPart();
        // 添加到邮件内容中
        body.addBodyPart(htmlPart);

        // html邮件内容
        MimeMultipart htmlMultipart = new MimeMultipart("alternative");// 纯文本与超文本共存
        htmlPart.setContent(htmlMultipart);
        MimeBodyPart htmlContent = new MimeBodyPart();
        htmlContent.setContent(info.getMailContent(),"text/html;charset=UTF-8");
        htmlMultipart.addBodyPart(htmlContent);

        // 保存邮件内容修改
        message.saveChanges();
        // 发送邮件
        transport(message);
    }

    /**
     * 初始化Message对象
     * @param info 发送邮件的信息
     * @return message
     * @throws MessagingException
     */
    public static Message initMessage(SendInfo info) throws MessagingException{

        // 判断是否需要身份验证
        MyAuthenticator authenticator = null;
        Properties props = info.getProperties();
        if(info.isValidate()){
            authenticator = new MyAuthenticator(info.getUserName(),info.getUserPassword());
        }

        /**
         * Session类定义了一个基本邮件会话（session）
         * Session类是Java Mail API最高层入口类
         * 根据props和authenticator构造发送邮件的Session对象
         * getInstance():直接提取;getDefaultInstance():若之前存在加载，不存在提取
         */
        Session session = Session.getInstance(props,authenticator);
        session.setDebug(true);// 打印调试信息

        /**
         * Message,MimeMessage用于创建要发送的信息
         * Message是一个抽象类，Message头只能被限制为用US-ASCII字符
         * MimeMessage能理解MIME类型和头的电子邮件信息
         * Address,InternetAddress用于确定信件地址
         */
        Message message = new MimeMessage(session);
        // 设置发件地址
        if(info.getFromAddress()!=null){
            Address from = new InternetAddress(info.getFromAddress());
            message.setFrom(from);
        }else{
            throw new MessagingException("异常：发件地址为空！");
        }
        // 设置收件地址
        if(info.getToAddress()!=null){
            for(String toAddress : info.getToAddress()){
                Address to = new InternetAddress(toAddress);
                message.addRecipient(Message.RecipientType.TO,to);
            }
        }else{
            System.out.println("错误：收件地址为空");
        }
        // 设置抄送地址
        if(info.getCcAddress()!=null){
            for(String ccAddress : info.getCcAddress()){
                Address cc = new InternetAddress(ccAddress);
                message.addRecipient(Message.RecipientType.CC,cc);
            }
        }
        // 设置密送地址
        if(info.getBccAddress()!=null){
            for(String bccAdress : info.getBccAddress()){
                Address bcc = new InternetAddress(bccAdress);
                message.addRecipient(Message.RecipientType.BCC,bcc);
            }
        }
        // 设置邮件主题
        message.setSubject(info.getMailSubject());
        // 设置邮件发送时间
        message.setSentDate(new Date());

        return message;
    }

    /**
     * 创建Transport对象根据session建立连接
     * @param message Message对象，可用getSession()获得Session对象
     * @throws MessagingException
     */
    public static void transport(Message message) throws MessagingException{

        /**
         * Transport用于消息发送的最后一部分
         * Transport静态方法send():一次只能发一份邮件
         * Transport无参方法connect()
         */
        // Transport.send(message);
        Transport transport = message.getSession().getTransport();
        transport.connect();
        transport.sendMessage(message,message.getAllRecipients());// 发送邮件，第2个参数为所有设置好的收件人地址
        transport.close();
    }

}
